package controllers

import (
	"fmt"
	"github.com/XieWeikai/PlaceToGo/models"
	"github.com/XieWeikai/PlaceToGo/utils"
	"github.com/gin-gonic/gin"
	"net/http"
	"strconv"
)

var responseKeyMap = map[string]string{
	"userId":              "user_id",
	"requestId":           "request_id",
	"responseDescription": "description",
	"responseImages":      "image_url",
	"creationTime":        "created_at",
	"modificationTime":    "updated_at",
}

func GetResponse(c *gin.Context) {
	var r models.Response
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(400, gin.H{"error": "invalid response id"})
		return
	}
	r.ID = uint(id)
	if _, err := r.GetFirst(); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}
	c.JSON(200, &r)
}

func GetResponses(c *gin.Context) {
	filter, err := utils.ParseFilter(c.DefaultQuery("filter", "{}"))
	filter = utils.ReplaceKeys(filter, responseKeyMap)
	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}
	l, r, err := utils.ParseRange(c.DefaultQuery("range", "[0, 9]"))
	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}
	sortBy, sortOrder, err := utils.ParseSort(c.DefaultQuery("sort", "[\"id\", \"asc\"]"))
	sortBy = responseKeyMap[sortBy]
	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}
	responses, cnt, err := models.GetResponses(filter, int(r-l+1), int(l), sortBy, sortOrder)
	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	c.Header("Content-Range", fmt.Sprintf("responses %d-%d/%d", l, r, cnt))
	c.JSON(200, responses)
}

func CreateResponse(c *gin.Context) {
	var r models.Response
	uid := c.MustGet("user_id").(uint)
	if err := c.ShouldBindJSON(&r); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}
	r.UserID = uid
	if _, err := r.CreateResponse(); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}
	c.JSON(201, gin.H{"data": &r})
}

func UpdateResponse(c *gin.Context) {
	var r models.Response
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(400, gin.H{"error": "invalid response id"})
		return
	}
	r.ID = uint(id)
	if _, err := r.GetFirst(); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}
	uid := c.MustGet("user_id").(uint)
	if r.UserID != uid && c.MustGet("user_type").(string) != "admin" {
		c.JSON(http.StatusForbidden, gin.H{"error": "you are not allowed to update this response"})
		return
	}

	dto := models.UpdateResponseDTO{}

	if err := c.ShouldBindJSON(&dto); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}
	if err := r.UpdateById(&dto); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	c.JSON(200, &r)
}

func CancelResponse(c *gin.Context) {
	var r models.Response
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(400, gin.H{"error": "invalid response id"})
		return
	}
	r.ID = uint(id)
	if _, err := r.GetFirst(); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}
	uid := c.MustGet("user_id").(uint)
	if r.UserID != uid {
		c.JSON(400, gin.H{"error": "you are not allowed to cancel this response"})
		return
	}

	if r.Status != models.Pending {
		c.JSON(400, gin.H{"error": "cannot cancel a response that is not pending"})
		return
	}

	if err := r.Cancel(); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}
	c.JSON(200, gin.H{"message": "response cancelled"})
}
